package org.hit.burkun.umls;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.hit.burkun.db.DBHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class BaseMapper {
	// 数据库连接
	protected DBHelper dbh;
	// 表名
	protected String tbName;
	// 使用in语句查询，所以不建议太多
	private int maxBatchNum = 300;

	private static Logger logger = LoggerFactory.getLogger(BaseMapper.class);
	// 统计未进行mapping的数据
	private int unmappedCounter = 0;

	public BaseMapper(DBHelper dbh, String tbName) {
		super();
		this.dbh = dbh.clone();
		this.tbName = tbName;
	}

	/**
	 * 进行初始化行为
	 */
	public void begin() {
		logger.debug("init connection...");
		dbh.connectionDB();
	}

	/**
	 * 执行向数据库的map动作
	 * 
	 * @param ids
	 *            来源id集合
	 * @param conceptFiled
	 *            umls conception的列名
	 * @param codeFiled
	 *            对应的来源的列明
	 * @param otherCondition
	 *            对应的筛选条件
	 */
	protected void map(Collection<String> ids, String conceptFiled,
			String codeFiled, String otherCondition) {
		unmappedCounter = ids.size();
		logger.debug("get map from " + tbName + "...");
		String sqlStr = assembleQueryStr(conceptFiled, codeFiled,
				otherCondition);
		logger.debug("get sqlquery template " + sqlStr);
		int counter = 0;
		StringBuilder sb = new StringBuilder();
		for (String id : ids) {
			if (counter == maxBatchNum) {
				sb.deleteCharAt(sb.length() - 1);
				String queryStr = String.format(sqlStr, sb.toString());
				Collection<String[]> res = dbh.queryData(queryStr, 2);
				Map<String, Set<String>> mapres = getMapedData(res);
				process(mapres);
				sb.setLength(0);
				sb.append("'" + id + "'").append(",");
				counter = 0;
			} else {
				sb.append("'" + id + "',");
			}
			counter += 1;
		}
		// 还有部分要继续处理吆~
		if (counter > 0) {
			sb.deleteCharAt(sb.length() - 1);
			String queryStr = String.format(sqlStr, sb.toString());
			Collection<String[]> res = dbh.queryData(queryStr, 2);
			Map<String, Set<String>> mapres = getMapedData(res);
			process(mapres);
			sb.setLength(0);
		}
	}

	/**
	 * 执行清理工作
	 */
	public void end() {
		if (unmappedCounter > 0) {
			logger.warn("there have " + unmappedCounter
					+ " can not map to umls conception");
		}
		logger.debug("clean connection...");
		dbh.disconnection();
	}

	/**
	 * 抽象函数，批量处理时会调用
	 * 
	 * @param data
	 *            传入处理完后的数据
	 */
	public abstract void process(Map<String, Set<String>> data);

	protected String assembleQueryStr(String conceptFiled, String codeFiled,
			String otherCondition) {
		StringBuilder sb = new StringBuilder();
		sb.append("select ").append(conceptFiled).append(", ")
				.append(codeFiled).append(" from ").append(tbName);
		sb.append(" where ").append(codeFiled).append(" in (%s) ");
		if (otherCondition != null) {
			sb.append("and ").append(otherCondition);
		}
		return sb.toString();
	}

	/**
	 * 把Collection 变成 hashmap
	 * 
	 * @param data
	 *            集合数据 sourceid -> mapped id
	 * @return
	 */
	protected Map<String, Set<String>> getMapedData(Collection<String[]> data) {
		logger.debug("convert data to Map<String, Set<String>>...");
		Map<String, Set<String>> table = new HashMap<String, Set<String>>();
		for (String[] arg : data) {
			String value = arg[0];
			String key = arg[1];
			if (table.containsKey(key)) {
				table.get(key).add(value);
			} else {
				HashSet<String> set = new HashSet<String>();
				set.add(value);
				table.put(key, set);
			}
		}
		unmappedCounter -= table.size();
		return table;
	}

}
